package cn.micro.eye.service.impl;

import cn.micro.eye.commons.auth.AuthContext;
import cn.micro.eye.commons.auth.MicroToken;
import cn.micro.eye.commons.exception.MicroBadRequestException;
import cn.micro.eye.commons.exception.MicroErrorException;
import cn.micro.eye.commons.mybatis.extension.MicroServiceImpl;
import cn.micro.eye.commons.utils.AESUtils;
import cn.micro.eye.commons.utils.IPUtils;
import cn.micro.eye.convert.MemberConvert;
import cn.micro.eye.entity.Account;
import cn.micro.eye.entity.Member;
import cn.micro.eye.entity.MemberRole;
import cn.micro.eye.mapper.IAccountMapper;
import cn.micro.eye.mapper.IMemberMapper;
import cn.micro.eye.mapper.IMemberRoleMapper;
import cn.micro.eye.model.add.AccountRegister;
import cn.micro.eye.model.query.AccountLogin;
import cn.micro.eye.service.IAccountService;
import cn.micro.eye.service.IMemberService;
import cn.micro.eye.type.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 账号表，Account-Member为1-1 服务实现类
 * </p>
 *
 * @author lry
 * @since 2018-10-07
 */
@Service
public class AccountServiceImpl extends MicroServiceImpl<IAccountMapper, Account> implements IAccountService {

    @Resource
    private IMemberMapper memberMapper;
    @Resource
    private IMemberRoleMapper memberRoleMapper;

    @Resource
    private IMemberService memberService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addRegister(AccountRegister accountRegister) throws Exception {
        // 注册数据校验
        accountRegister.validate();

        // 账号唯一性校验
        Account account = super.getOneEqs(Account::getOpenId, accountRegister.getOpenId());
        if (account != null) {
            if (RegisterTypeEnum.EMAIL.getValue() == accountRegister.getRegisterType()) {
                throw new MicroBadRequestException("邮箱地址已存在");
            } else if (RegisterTypeEnum.PHONE.getValue() == accountRegister.getRegisterType()) {
                throw new MicroBadRequestException("手机号码已存在");
            } else if (RegisterTypeEnum.ID_CARD.getValue() == accountRegister.getRegisterType()) {
                throw new MicroBadRequestException("身份证号码已存在");
            } else {
                throw new MicroBadRequestException("账号已存在");
            }
        }

        // 检查账号是否存在用户信息
        Member queryMember = this.buildRegisterMember(accountRegister);
        Member member = memberMapper.selectOne(Wrappers.query(queryMember));
        if (member == null) {
            // 没有用户信息,则立即注册一条用户信息
            member = MemberConvert.INSTANCE.copy(queryMember);
            member.setHeadImgUrl(memberService.randomHeadImgUrl());
            member.setCategory(MemberCategoryEnum.ORDINARY.getValue());
            member.setResource(MemberResourceEnum.AUTO_REG.getValue());
            member.setPassword(AESUtils.encode(accountRegister.getPassword()));
            if (memberMapper.insert(member) <= 0) {
                throw new MicroErrorException("用户注册失败");
            }
        }

        // 注册账号
        Account insertAccount = new Account();
        insertAccount.setRegisterIp(IPUtils.getIPAddress());
        insertAccount.setOpenId(accountRegister.getOpenId());
        insertAccount.setRegisterType(accountRegister.getRegisterType());
        // 用户信息不为空则直接绑定关系
        insertAccount.setMemberId(member.getId());
        if (baseMapper.insert(insertAccount) <= 0) {
            throw new MicroErrorException("账号注册失败");
        }

        // 分配角色
        MemberRole memberRole = new MemberRole();
        memberRole.setRoleId((long) RoleEnum.ROLE_USER.getValue());
        memberRole.setMemberId(member.getId());
        return memberRoleMapper.insert(memberRole) > 0;
    }

    @Override
    public MicroToken queryLogin(AccountLogin accountLogin) throws Exception {
        // 注册数据校验
        accountLogin.validate();

        // 校验账号信息
        Account queryAccount = new Account();
        queryAccount.setOpenId(accountLogin.getOpenId());
        Account account = baseMapper.selectOne(Wrappers.query(queryAccount));
        if (account == null) {
            throw new MicroBadRequestException("账号不存在");
        }
        if (account.getMemberId() == null) {
            throw new MicroBadRequestException("未绑定用户");
        }

        // 校验用户信息
        Member queryMember = this.buildQueryMember(account);
        Member member = memberMapper.selectOne(new QueryWrapper<>(queryMember));
        if (member == null) {
            throw new MicroBadRequestException("未找到用户");
        }
        if (StringUtils.isBlank(member.getPassword())) {
            throw new MicroBadRequestException("未设置密码");
        }
        if (!member.getPassword().equals(AESUtils.encode(accountLogin.getPassword()))) {
            throw new MicroBadRequestException("密码错误");
        }

        // 查询当前用户的所有角色
        List<String> roleCodes = memberRoleMapper.selectRoleCodesByMemberId(member.getId());
        if (CollectionUtils.isEmpty(roleCodes)) {
            throw new MicroBadRequestException("用户未分配角色");
        }

        // 自动纠正数据
        if (StringUtils.isBlank(member.getHeadImgUrl())) {
            Member updateMember = new Member();
            updateMember.setId(member.getId());
            updateMember.setHeadImgUrl(memberService.randomHeadImgUrl());
            if (memberService.updateById(updateMember)) {
                member.setHeadImgUrl(updateMember.getHeadImgUrl());
            }
        }

        return AuthContext.build(member.getId(), member.getName(),
                String.valueOf(accountLogin.getCategory()), roleCodes, null);
    }

    private Member buildQueryMember(Account account) {
        return this.buildOpenId(account.getOpenId(), account.getRegisterType());
    }

    private Member buildRegisterMember(AccountRegister accountRegister) {
        Member member = this.buildOpenId(accountRegister.getOpenId(), accountRegister.getRegisterType());
        member.setName(accountRegister.getName());
        return member;
    }

    private Member buildOpenId(String openId, Integer registerType) {
        Member member = new Member();
        if (RegisterTypeEnum.EMAIL.getValue() == registerType) {
            member.setEmail(openId);
        } else if (RegisterTypeEnum.PHONE.getValue() == registerType) {
            member.setMobile(openId);
        } else if (RegisterTypeEnum.ID_CARD.getValue() == registerType) {
            member.setIdCard(openId);
        }

        return member;
    }

}
